package com.sen.gulimall.ware.listener;

import com.rabbitmq.client.Channel;
import com.sen.common.constant.WareCacheConst;
import com.sen.common.constant.WareConstant;
import com.sen.common.to.mq.OrderTo;
import com.sen.common.to.mq.StockLockedTo;
import com.sen.gulimall.ware.service.WareSkuService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

/**
 * @author Kisen
 * @email lqs0911@qq.com
 * @date 2023/1/13 10:58
 * @detail
 */
@Slf4j
@Service
@RabbitListener(queues = WareConstant.STOCK_RELEASE_STOCK_QUEUE)
public class StockReleaseListener {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private WareSkuService wareSkuService;

    /**
     * 1、库存自动解锁。
     * 下订单成功，库存锁定成功，接下来的业务调用失败，导致订单回滚。之前锁定的库存就要自动解锁。
     * 2、订单失败。
     * 锁库存失败
     *
     * @param to
     * @param message
     * @param channel
     * @throws IOException
     */
    @RabbitHandler
    public void handleStockLockedRelease(StockLockedTo to, Message message, Channel channel) throws IOException {
        String messageId = message.getMessageProperties().getHeader("spring_returned_message_correlation");
        log.info("队列{}已经接收到id为{}的消息：{}", WareConstant.STOCK_RELEASE_STOCK_QUEUE, messageId, to);

        try {
            String fullKey = WareCacheConst.STOCK_RELEASE_STOCK_KEY + messageId;
            Boolean flag = redisTemplate.hasKey(fullKey);
            //redis中不存在，则说明消息没有消费过，按正常业务处理；否则，直接跳过
            if (!flag) {

                wareSkuService.unlockStock(to);

                //存入redis
                redisTemplate.opsForValue().setIfAbsent(fullKey, fullKey, WareCacheConst.MQ_MESSAGE_ID_CACHE_TIMEOUT_DAYS, TimeUnit.DAYS);
            }

            //TODO:记录消息日志：消费成功
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);

        } catch (Exception e) {
            //业务异常，不重回队列，而是放入死信队列处理
            log.error("队列{}接收到id为{}的消息：{}，处理业务异常：{}", WareConstant.STOCK_RELEASE_STOCK_QUEUE, messageId, to, e);

            //TODO:记录消息日志：消费失败
            channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
        }
    }


    @RabbitHandler
    public void handleOrderCloseRelease(OrderTo to, Message message, Channel channel) throws IOException {
        String messageId = message.getMessageProperties().getHeader("spring_returned_message_correlation");
        log.info("队列{}已经接收到id为{}的消息：{}", WareConstant.STOCK_RELEASE_STOCK_QUEUE, messageId, to);

        try {
            String fullKey = WareCacheConst.STOCK_RELEASE_STOCK_KEY + messageId;
            Boolean flag = redisTemplate.hasKey(fullKey);
            //redis中不存在，则说明消息没有消费过，按正常业务处理；否则，直接跳过
            if (!flag) {

                log.info("订单关闭准备解锁库存");
                wareSkuService.unlockStock(to);

                //存入redis
                redisTemplate.opsForValue().setIfAbsent(fullKey, fullKey, WareCacheConst.MQ_MESSAGE_ID_CACHE_TIMEOUT_DAYS, TimeUnit.DAYS);
            }

            //TODO:记录消息日志：消费成功
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);

        } catch (Exception e) {
            //业务异常，不重回队列，而是放入死信队列处理
            log.error("队列{}接收到id为{}的消息：{}，处理业务异常：{}", WareConstant.STOCK_RELEASE_STOCK_QUEUE, messageId, to, e);

            //TODO:记录消息日志：消费失败
            channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, true);
        }
    }
}
